"""
数据采集引擎
负责管理设备连接、数据采集调度和数据分发
"""

import threading
import time
import queue
import logging
from concurrent.futures import ThreadPoolExecutor, as_completed
from datetime import datetime
from typing import Dict, List, Optional, Callable, Any
from dataclasses import dataclass

from .base_driver import BaseDriver, TagValue, ConnectionStatus

@dataclass
class CollectionTask:
    """数据采集任务"""
    device_name: str
    driver: BaseDriver
    last_collection_time: float = 0
    next_collection_time: float = 0
    error_count: int = 0
    enabled: bool = True

class DataEngine:
    """数据采集引擎"""
    
    def __init__(self, storage_service=None, alarm_service=None, max_workers=10):
        self.devices: Dict[str, BaseDriver] = {}
        self.collection_tasks: Dict[str, CollectionTask] = {}
        self.running = False
        self.paused = False
        
        # 线程池
        self.executor = ThreadPoolExecutor(max_workers=max_workers, thread_name_prefix="DataEngine")
        
        # 数据队列
        self.data_queue = queue.Queue(maxsize=10000)
        
        # 服务引用
        self.storage_service = storage_service
        self.alarm_service = alarm_service
        
        # 回调函数
        self.data_callbacks: List[Callable[[List[TagValue]], None]] = []
        
        # 统计信息
        self.stats = {
            'total_collections': 0,
            'successful_collections': 0,
            'failed_collections': 0,
            'last_collection_time': None,
            'data_points_per_second': 0,
            'connected_devices': 0,
            'total_devices': 0
        }
        
        # 线程控制
        self.lock = threading.RLock()
        self.collection_thread = None
        self.data_processing_thread = None
        
        self.logger = logging.getLogger(self.__class__.__name__)
    
    def add_device(self, device_name: str, driver: BaseDriver):
        """添加设备"""
        with self.lock:
            self.devices[device_name] = driver
            self.collection_tasks[device_name] = CollectionTask(
                device_name=device_name,
                driver=driver,
                enabled=driver.enabled
            )
            self.logger.info(f"添加设备: {device_name}")
            self._update_stats()
    
    def remove_device(self, device_name: str):
        """移除设备"""
        with self.lock:
            if device_name in self.devices:
                driver = self.devices[device_name]
                driver.disconnect()
                del self.devices[device_name]
                del self.collection_tasks[device_name]
                self.logger.info(f"移除设备: {device_name}")
                self._update_stats()
    
    def get_device(self, device_name: str) -> Optional[BaseDriver]:
        """获取设备驱动"""
        return self.devices.get(device_name)
    
    def start(self):
        """启动数据采集引擎"""
        if self.running:
            self.logger.warning("数据采集引擎已在运行")
            return
        
        self.running = True
        self.paused = False
        
        # 启动采集线程
        self.collection_thread = threading.Thread(
            target=self._collection_worker,
            name="DataCollectionWorker"
        )
        self.collection_thread.daemon = True
        self.collection_thread.start()
        
        # 启动数据处理线程
        self.data_processing_thread = threading.Thread(
            target=self._data_processing_worker,
            name="DataProcessingWorker"
        )
        self.data_processing_thread.daemon = True
        self.data_processing_thread.start()
        
        self.logger.info("数据采集引擎已启动")
    
    def stop(self):
        """停止数据采集引擎"""
        if not self.running:
            return
        
        self.running = False
        
        # 断开所有设备连接
        with self.lock:
            for driver in self.devices.values():
                try:
                    driver.disconnect()
                except Exception as e:
                    self.logger.error(f"断开设备连接失败: {e}")
        
        # 关闭线程池
        self.executor.shutdown(wait=True)
        
        self.logger.info("数据采集引擎已停止")
    
    def pause(self):
        """暂停数据采集"""
        self.paused = True
        self.logger.info("数据采集已暂停")
    
    def resume(self):
        """恢复数据采集"""
        self.paused = False
        self.logger.info("数据采集已恢复")
    
    def enable_device(self, device_name: str):
        """启用设备"""
        with self.lock:
            if device_name in self.collection_tasks:
                self.collection_tasks[device_name].enabled = True
                self.logger.info(f"设备 {device_name} 已启用")
    
    def disable_device(self, device_name: str):
        """禁用设备"""
        with self.lock:
            if device_name in self.collection_tasks:
                self.collection_tasks[device_name].enabled = False
                # 断开连接
                if device_name in self.devices:
                    self.devices[device_name].disconnect()
                self.logger.info(f"设备 {device_name} 已禁用")
    
    def add_data_callback(self, callback: Callable[[List[TagValue]], None]):
        """添加数据回调函数"""
        self.data_callbacks.append(callback)
    
    def remove_data_callback(self, callback: Callable[[List[TagValue]], None]):
        """移除数据回调函数"""
        if callback in self.data_callbacks:
            self.data_callbacks.remove(callback)
    
    def get_device_status(self, device_name: str) -> Optional[Dict[str, Any]]:
        """获取设备状态"""
        if device_name not in self.devices:
            return None
        
        driver = self.devices[device_name]
        task = self.collection_tasks[device_name]
        
        return {
            'device_name': device_name,
            'enabled': task.enabled,
            'connection_status': driver.connection_status.value,
            'last_collection_time': datetime.fromtimestamp(task.last_collection_time) if task.last_collection_time > 0 else None,
            'next_collection_time': datetime.fromtimestamp(task.next_collection_time) if task.next_collection_time > 0 else None,
            'error_count': task.error_count,
            'health_check': driver.health_check()
        }
    
    def get_all_devices_status(self) -> List[Dict[str, Any]]:
        """获取所有设备状态"""
        return [self.get_device_status(name) for name in self.devices.keys()]
    
    def get_statistics(self) -> Dict[str, Any]:
        """获取引擎统计信息"""
        with self.lock:
            self.stats['total_devices'] = len(self.devices)
            self.stats['connected_devices'] = sum(
                1 for driver in self.devices.values() 
                if driver.connection_status == ConnectionStatus.CONNECTED
            )
            return self.stats.copy()
    
    def _collection_worker(self):
        """数据采集工作线程"""
        self.logger.info("数据采集工作线程已启动")
        
        while self.running:
            try:
                if self.paused:
                    time.sleep(0.1)
                    continue
                
                current_time = time.time()
                
                # 查找需要采集的设备
                tasks_to_run = []
                with self.lock:
                    for task in self.collection_tasks.values():
                        if not task.enabled:
                            continue
                            
                        driver = task.driver
                        
                        # 计算下次采集时间
                        if task.next_collection_time == 0:
                            task.next_collection_time = current_time
                        
                        if current_time >= task.next_collection_time:
                            tasks_to_run.append(task)
                            task.next_collection_time = current_time + driver.polling_interval
                
                # 提交采集任务到线程池
                if tasks_to_run:
                    future_to_task = {
                        self.executor.submit(self._collect_device_data, task): task
                        for task in tasks_to_run
                    }
                    
                    # 等待任务完成
                    for future in as_completed(future_to_task, timeout=30):
                        task = future_to_task[future]
                        try:
                            result = future.result()
                            if result:
                                task.last_collection_time = current_time
                                task.error_count = 0
                                self.stats['successful_collections'] += 1
                            else:
                                task.error_count += 1
                                self.stats['failed_collections'] += 1
                        except Exception as e:
                            self.logger.error(f"设备 {task.device_name} 采集异常: {e}")
                            task.error_count += 1
                            self.stats['failed_collections'] += 1
                        
                        self.stats['total_collections'] += 1
                        self.stats['last_collection_time'] = datetime.now()
                
                # 短暂休眠
                time.sleep(0.1)
                
            except Exception as e:
                self.logger.error(f"采集工作线程异常: {e}")
                time.sleep(1)
        
        self.logger.info("数据采集工作线程已停止")
    
    def _collect_device_data(self, task: CollectionTask) -> bool:
        """采集单个设备数据"""
        driver = task.driver
        
        try:
            # 检查连接状态
            if not driver.is_connected():
                if not driver.auto_reconnect():
                    return False
            
            # 读取所有标签
            tag_values = driver.read_all_tags()
            
            if tag_values:
                # 将数据放入队列
                try:
                    self.data_queue.put(tag_values, timeout=1)
                except queue.Full:
                    self.logger.warning("数据队列已满，丢弃数据")
                    return False
                
                return True
            else:
                return False
                
        except Exception as e:
            self.logger.error(f"设备 {task.device_name} 数据采集失败: {e}")
            return False
    
    def _data_processing_worker(self):
        """数据处理工作线程"""
        self.logger.info("数据处理工作线程已启动")
        
        data_count = 0
        last_stats_time = time.time()
        
        while self.running:
            try:
                # 从队列获取数据
                try:
                    tag_values = self.data_queue.get(timeout=1)
                except queue.Empty:
                    continue
                
                # 处理数据
                self._process_data(tag_values)
                data_count += len(tag_values)
                
                # 更新统计信息
                current_time = time.time()
                if current_time - last_stats_time >= 5:  # 每5秒更新一次
                    time_diff = current_time - last_stats_time
                    self.stats['data_points_per_second'] = data_count / time_diff
                    data_count = 0
                    last_stats_time = current_time
                
                self.data_queue.task_done()
                
            except Exception as e:
                self.logger.error(f"数据处理异常: {e}")
        
        self.logger.info("数据处理工作线程已停止")
    
    def _process_data(self, tag_values: List[TagValue]):
        """处理采集到的数据"""
        try:
            # 存储数据
            if self.storage_service:
                self.storage_service.save_tag_values(tag_values)
            
            # 检查报警
            if self.alarm_service:
                for tag_value in tag_values:
                    self.alarm_service.check_alarm(tag_value)
            
            # 调用回调函数
            for callback in self.data_callbacks:
                try:
                    callback(tag_values)
                except Exception as e:
                    self.logger.error(f"数据回调函数执行失败: {e}")
                    
        except Exception as e:
            self.logger.error(f"数据处理失败: {e}")
    
    def _update_stats(self):
        """更新统计信息"""
        with self.lock:
            self.stats['total_devices'] = len(self.devices)
            self.stats['connected_devices'] = sum(
                1 for driver in self.devices.values() 
                if driver.connection_status == ConnectionStatus.CONNECTED
            )
    
    def write_device_tag(self, device_name: str, tag_name: str, value: Any) -> bool:
        """写入设备标签值"""
        if device_name not in self.devices:
            self.logger.error(f"设备 {device_name} 不存在")
            return False
        
        driver = self.devices[device_name]
        
        try:
            return driver.write_tag(tag_name, value)
        except Exception as e:
            self.logger.error(f"写入设备 {device_name} 标签 {tag_name} 失败: {e}")
            return False
    
    def get_device_info(self, device_name: str = None) -> Dict[str, Any]:
        """获取设备信息"""
        if device_name:
            # 获取单个设备信息
            if device_name not in self.devices:
                return {}
            
            driver = self.devices[device_name]
            task = self.collection_tasks[device_name]
            device_info = driver.get_device_info()
            
            device_info.update({
                'enabled': task.enabled,
                'connection_status': driver.connection_status.value,
                'last_collection_time': datetime.fromtimestamp(task.last_collection_time) if task.last_collection_time > 0 else None,
                'error_count': task.error_count,
                'collected_points': len(driver.latest_data) if hasattr(driver, 'latest_data') else 0
            })
            
            return device_info
        else:
            # 获取所有设备信息
            devices_info = []
            for name, driver in self.devices.items():
                task = self.collection_tasks[name]
                device_info = driver.get_device_info()
                
                device_info.update({
                    'enabled': task.enabled,
                    'connection_status': driver.connection_status.value,
                    'last_collection_time': datetime.fromtimestamp(task.last_collection_time) if task.last_collection_time > 0 else None,
                    'error_count': task.error_count,
                    'collected_points': len(driver.latest_data) if hasattr(driver, 'latest_data') else 0
                })
                
                devices_info.append(device_info)
            
            return devices_info
    
    def reload_device_config(self, device_name: str = None):
        """重新加载设备配置"""
        try:
            if device_name:
                # 重新加载单个设备
                if device_name in self.devices:
                    self.logger.info(f"重新加载设备配置: {device_name}")
                    driver = self.devices[device_name]
                    # 重新连接设备
                    driver.disconnect()
                    driver.connect()
                else:
                    self.logger.warning(f"设备 {device_name} 不存在，无法重新加载")
            else:
                # 重新加载所有设备
                self.logger.info("重新加载所有设备配置")
                for device_name, driver in self.devices.items():
                    driver.disconnect()
                    driver.connect()
        except Exception as e:
            self.logger.error(f"重新加载设备配置失败: {e}")
    
    def update_device_config(self, device_name: str, config: Dict[str, Any]):
        """更新设备配置"""
        try:
            if device_name in self.devices:
                driver = self.devices[device_name]
                # 更新驱动配置
                driver.update_config(config)
                # 重新连接
                driver.disconnect()
                driver.connect()
                self.logger.info(f"更新设备配置: {device_name}")
            else:
                self.logger.warning(f"设备 {device_name} 不存在")
        except Exception as e:
            self.logger.error(f"更新设备配置失败: {e}")
    
    def get_device_latest_data(self, device_name: str) -> Dict[str, Any]:
        """获取设备最新数据"""
        if device_name not in self.devices:
            return {}
        
        driver = self.devices[device_name]
        if hasattr(driver, 'latest_data'):
            return driver.latest_data
        return {}
    
    def get_latest_data(self, device_name: str) -> List[Dict[str, Any]]:
        """获取设备最新数据（与web API兼容的格式）"""
        if device_name not in self.devices:
            return []
        
        driver = self.devices[device_name]
        if hasattr(driver, 'latest_data') and driver.latest_data:
            # 将latest_data字典转换为列表格式
            result = []
            for tag_name, tag_value in driver.latest_data.items():
                if isinstance(tag_value, TagValue):
                    result.append({
                        'tag_name': tag_value.tag_name,
                        'value': tag_value.value,
                        'timestamp': tag_value.timestamp.isoformat() if isinstance(tag_value.timestamp, datetime) else tag_value.timestamp,
                        'quality': tag_value.quality,
                        'device_name': tag_value.device_name
                    })
                else:
                    # 兼容其他格式
                    result.append({
                        'tag_name': tag_name,
                        'value': tag_value,
                        'timestamp': datetime.now().isoformat(),
                        'quality': 'GOOD',
                        'device_name': device_name
                    })
            return result
        return []
    
    def get_all_latest_data(self) -> Dict[str, Dict[str, Any]]:
        """获取所有设备的最新数据"""
        all_data = {}
        for device_name in self.devices:
            all_data[device_name] = self.get_device_latest_data(device_name)
        return all_data 